package com.wxd.woff;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created with IntelliJ IDEA. open true font
 *
 * @author: wangxindong
 * @date: 2018/8/29-21:01
 */
public class ByteBufferOTFDataStream extends AbstractOTFDataStream {

    private static final Logger LOGGER = LoggerFactory.getLogger(ByteBufferOTFDataStream.class);

    /**
     * 存放数据的byte数组
     */
    private byte[] data = null;
    /**
     * 当前索引，读取数据的位置
     */
    private int currentPosition = 0;

    public ByteBufferOTFDataStream() {

    }

    /**
     * @param input The stream to read from. It will be closed by this method.
     * @throws IOException
     */
    public ByteBufferOTFDataStream(InputStream input) throws IOException {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream(input.available())) {
            byte[] buffer = new byte[1024];
            int amountRead = 0;
            while ((amountRead = input.read(buffer)) != -1) {
                out.write(buffer, 0, amountRead);
            }
            // write input data
            data = out.toByteArray();
        } catch (IOException e) {
            LOGGER.error("read data error {}", e);
            throw new RuntimeException("read data error {}", e);
        } finally {
            input.close();
        }
    }

    public ByteBufferOTFDataStream(String input, String charset) throws IOException {
        byte[] bs = input.getBytes(charset);
        data = bs;
    }

    public ByteBufferOTFDataStream(byte[] input) throws IOException {
        data = input;
        currentPosition = 0;
    }

    /**
     * read a byte from data array 1 byte
     *
     * @return
     * @throws IOException
     */
    @Override
    public int read() throws IOException {
        if (currentPosition >= data.length) {
            return -1;
        }
        int retval = data[currentPosition];
        currentPosition++;
        return retval & 0xFF;
    }

    /**
     * read a long value 8 byte
     *
     * @return
     * @throws IOException
     */
    @Override
    public long readLong() throws IOException {
        return ((long)(readInt()) << 32) + (readInt() & 0xFFFFFFFFL);
    }

    /**
     * Read a signed integer.
     *
     * @return A signed integer.
     * @throws IOException If there is a problem reading the file.
     */
    public int readSignedInt() throws IOException {
        int ch1 = read();
        int ch2 = read();
        int ch3 = read();
        int ch4 = read();
        if ((ch1 | ch2 | ch3 | ch4) < 0) {
            throw new EOFException();
        }
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

    @Override
    public int readUnsignedShort() throws IOException {
        int ch1 = read();
        int ch2 = read();
        if ((ch1 | ch2) < 0) {
            throw new EOFException();
        }
        return (ch1 << 8) + (ch2 << 0);
    }

    @Override
    public short readSignedShort() throws IOException {
        int ch1 = read();
        int ch2 = read();
        if ((ch1 | ch2) < 0) {
            throw new EOFException();
        }
        return (short) ((ch1 << 8) + (ch2 << 0));
    }

    @Override
    public void seek(long pos) throws IOException {
        currentPosition = (int) pos;
    }

    /**
     * read data to b
     *
     * @param b
     * @param off
     * @param len
     * @return
     * @throws IOException
     */
    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        // check
        if (currentPosition < data.length) {
            int amountRead = Math.min(len, data.length - currentPosition);
            System.arraycopy(data, currentPosition, b, off, amountRead);
            currentPosition += amountRead;
            return amountRead;
        } else {
            return -1;
        }
    }

    /**
     * current position index
     *
     * @return
     * @throws IOException
     */
    @Override
    public long getCurrentPosition() throws IOException {
        return currentPosition;
    }

    @Override
    public InputStream getOriginalData() throws IOException {
        return new ByteArrayInputStream(data);
    }

    /**
     * data size
     *
     * @return data length
     */
    @Override
    public long getOriginalDataSize() {
        return data.length;
    }
}
